package net.m2technologies.open_arm.utilities;

import gnu.getopt.Getopt;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * Copyright 2005 Mark Masterson<br> <br> Licensed under the Apache License, Version 2.0 (the "License");<br> you may
 * not use this file except in compliance with the License.<br> You may obtain a copy of the License at<br> <br>
 * http://www.apache.org/licenses/LICENSE-2.0<br> <br> Unless required by applicable law or agreed to in writing,
 * software<br> distributed under the License is distributed on an "AS IS" BASIS,<br> WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, either express or implied.<br> See the License for the specific language governing permissions and<br>
 * limitations under the License.<br>
 * <p/>
 * <p>Description: This class parses a String array, passed as command line parameters to an executable class, via the
 * #main method.  The class will always parse the array passed to the constructor into a) a String, which can be
 * obtained via the method #getOriginalCommandLine, and b) a Collection, where each delimited element of the original
 * array becomes an element of the Collection.  The default delimiter, if none is specified, is a blank.  The resulting
 * Collection can be obtained via the method #getArgumentList</p> If these simple represenations are not sufficient, you
 * can pass an object to the constructors that implements the CommandLineParserStrategy interface.  This object will be
 * used to further parse the the Collection of delimited elements, placing the results into an Object of whatever
 * complexity is desired or needed. This parsed result object can then be obtained via the method #getParsedResult<p>
 *
 * @author Mark Masterson
 * @version 0.010
 */
public class CommandLineParser {

    private final Collection argumentList;
    private final String originalCommandLine;
    private final String delimiter;
    private final String[] originalArguments;
    private final Map parsedResult;

    public CommandLineParser(final String[] originalCommandLineArguments,
                             final CommandLineParserStrategy strategy) {
        this.originalArguments = originalCommandLineArguments;
        this.originalCommandLine = Strings.convertStringArrayToString(originalCommandLineArguments);
        this.delimiter = " ";
        this.argumentList = Strings.parseStringToCollection(this.originalCommandLine, this.delimiter);
        this.parsedResult = null != strategy ? strategy.parseCommandLine(this.argumentList) : Collections.EMPTY_MAP;
    }

    public CommandLineParser(final String[] originalCommandLineArguments,
                             final String commandLineDelimiter,
                             final CommandLineParserStrategy strategy) {
        this.originalArguments = originalCommandLineArguments;
        this.originalCommandLine = Strings.convertStringArrayToString(originalCommandLineArguments);
        this.delimiter = commandLineDelimiter;
        this.argumentList = Strings.parseStringToCollection(this.originalCommandLine, this.delimiter);
        this.parsedResult = null != strategy ? strategy.parseCommandLine(this.argumentList) : Collections.EMPTY_MAP;
    }

    public Collection getArgumentList() {
        return Collections.unmodifiableCollection(this.argumentList);
    }

    public String getOriginalCommandLine() {
        return this.originalCommandLine;
    }

    public String getDelimiter() {
        return this.delimiter;
    }

    public String[] getOriginalArguments() {
        return this.originalArguments;
    }

    public Object getParsedResult() {
        return Collections.unmodifiableMap(this.parsedResult);
    }

    public static interface CommandLineParserStrategy {

        Map parseCommandLine(final Collection arguments);
    }

    public static class PosixGetOptCommandLineParserStrategyImpl implements CommandLineParserStrategy {

        private final String applicationName;
        private final String commandLineOptionsDefintions;
        private final String[] originalCommandLineArguments;

        public PosixGetOptCommandLineParserStrategyImpl(final String applicationName,
                                                        final String commandLineOptionsDefintions,
                                                        final String[] originalCommandLineArguments) {
            this.applicationName = applicationName;
            this.commandLineOptionsDefintions = commandLineOptionsDefintions;
            this.originalCommandLineArguments = originalCommandLineArguments;
        }

        public Map parseCommandLine(final Collection arguments) {
            final Getopt posixCommandLineParser = new Getopt(this.applicationName,
                                                             this.originalCommandLineArguments,
                                                             this.commandLineOptionsDefintions);
            posixCommandLineParser.setOpterr(false);
            int index;
            final Map result = new HashMap();
            while (-1 != (index = posixCommandLineParser.getopt())) {
                result.put(new Character((char) index), posixCommandLineParser.getOptarg());
            }
            return result;
        }
    }
}
